
#include "string.h"
#include <stdio.h>
#include "stdlib.h"
#include "stdarg.h"

#include "serialHMI_struct.h"
#include "serialHMI_analysis.h"
#include "serialHMI_ex_api.h"

#include "ringbuff.h"
#include "crc.h"

#include "at_cmd_analyse.h"
#include "robot_interact.h"

STR_HMI_HANDLE hmi_handle;

// HMI receive frame buffer
STR_HMI_FRAME  hmi_frame_buffer[NUM_FRAME_BUF_MAX];
uint8_t  frame_buffer_payload[NUM_FRAME_BUF_MAX][8];

// HMI send frame
STR_HMI_FRAME  hmi_data_transmit;
STR_HMI_FRAME  hmi_plot_transmit;
STR_HMI_FRAME  hmi_ack_transmit;

uint8_t  default_transmit_payload[8];

// data struct rece from HMI 
STR_HMI_FUNNUM    funnum;
STR_HMI_KEYCMD    keycmd;
STR_HMI_KEYVALUE  keyValue;
STR_HMI_KEYREF    keyRefX1;
STR_HMI_KEYREF    keyRefX2;

STR_HMI_PLOTCMD   plotcmd;

// data struc transmit from MCU
STR_HMI_DATALIST  datalist;
STR_HMI_DATALIST  paramlist;
STR_HMI_CMDACK    ack;
STR_HMI_PLOTDATA  plotdata;

static uint8_t rece_data_buf[256];

static uint8_t param_write_flag = 0;

/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

static void byte_data_copy(uint8_t *dest, uint8_t *source, uint16_t length)
{
	uint8_t *traget = dest;
	uint8_t *start  = source;
	
	for(uint16_t i = 0; i < length; i++)
	{
		*(traget++) = *(start++);
	}
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void serialHMI_init(uint16_t device_num)
{
	// initial HMI receive frame buffer
	
	for(uint8_t i=0; i<NUM_FRAME_BUF_MAX; i++)
	{
		hmi_frame_buffer[i].ID = 0x1800 + device_num;
		hmi_frame_buffer[i].databuf = &frame_buffer_payload[i][0];
	}
	
	// initial HMI send frame
	hmi_data_transmit.head = HMI_FRAME_HEAD;
	hmi_data_transmit.databuf = &default_transmit_payload[0];
	hmi_data_transmit.length = HMI_COMM_FRAME_LENGTH;
	hmi_data_transmit.ID = ID_ACK_MCU_DATA;
	
	hmi_plot_transmit.head = HMI_FRAME_HEAD;
	hmi_plot_transmit.databuf = &default_transmit_payload[0];
	hmi_plot_transmit.length = HMI_COMM_FRAME_LENGTH;
	hmi_plot_transmit.ID = ID_ACK_MCU_PLOT;
	
	hmi_ack_transmit.head = HMI_FRAME_HEAD;
	hmi_ack_transmit.databuf = &default_transmit_payload[0];
	hmi_ack_transmit.length = HMI_COMM_FRAME_LENGTH;
	hmi_ack_transmit.ID = ID_ACK_MCU_PARAM;
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

uint8_t rece_buf_analysis(STR_RINGBUF* bufhdl, STR_HMI_FRAME* frame)
{
	uint8_t  rece_num_cnt = 0;
	uint16_t length = 0;
	
	STR_HMI_FRAME* p_frame = frame;
	
	length = ringBufRead(bufhdl, (char*)rece_data_buf, NUM_HMI_RECE_BUF_MAX);
	
	if(length < 2)
	{
		return rece_num_cnt;
	}
	
	for(uint16_t i = 0; i < length; i++)
	{
		if((rece_data_buf[i] == 0xF0) && (rece_data_buf[i + 1] == 0xF0))
		{
			uint16_t frame_ID = 0;
			uint16_t CRC_rslt = 0;
			uint8_t  CRC_flg = 0;
			
			if(length < 18)
			{
				return rece_num_cnt;
			}
			
			p_frame->head   = rece_data_buf[i + 0] + (rece_data_buf[i + 1] << 8);			
			p_frame->count  = rece_data_buf[i + 2] + (rece_data_buf[i + 3] << 8);			
			p_frame->length = rece_data_buf[i + 4] + (rece_data_buf[i + 5] << 8);
			
			frame_ID = rece_data_buf[i + 6] + (rece_data_buf[i + 7] << 8);
			
			
			if((frame_ID != p_frame->ID) && (frame_ID != ID_CMD_HMI_TO_MCU))
			{
				#if 1
				return rece_num_cnt;
				#endif
			}
			
			if(p_frame->length != 0x000A)
			{
				continue;
			}
			
			if((i + 6 + p_frame->length + 1) > length)
			{
				return rece_num_cnt;
			}
			
			p_frame->CRC_L = rece_data_buf[i + 6 + p_frame->length];
			p_frame->CRC_H = rece_data_buf[i + 6 + p_frame->length + 1];
			
			CRC_rslt = p_frame->CRC_L + (p_frame->CRC_H << 8);
			
			
			CRC_flg = checkCRC(&rece_data_buf[i + 6], p_frame->length, CRC_rslt);
			
			if(CRC_flg != 1)
			{
				continue;
			}
			else
			{
				memcpy(p_frame->databuf, &rece_data_buf[i+8], p_frame->length - 2);
				
				rece_num_cnt++;
				
				if(rece_num_cnt >= NUM_FRAME_BUF_MAX)
				{
					break;
				}
				
				p_frame++;
			}
		}
		
		else if((rece_data_buf[i] == 'A') && (rece_data_buf[i + 1] == 'T'))
		{
			uint8_t AT_end_flg = 0;
			
			if(length > LENGTH_AT_CMD_MAX)
			{
				continue;
			}
			
			for(uint16_t k = i; k < length; k++)
			{
				if(rece_data_buf[k] == '%')
				{
					AT_end_flg = 1;
					break;
				}
			}
			
			if(AT_end_flg == 1)
			{
				fac_at_parse((char*)&rece_data_buf[i], length - i);	
			}
		}
	}
	
	return rece_num_cnt;
}




/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void send_buf_packing(STR_RINGBUF* bufhdl, STR_HMI_FRAME* frame)
{
	
	uint16_t crc_value   = 0;
	
	uint8_t *databuf_p = frame->databuf;
	uint8_t  crc_buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	
	static uint16_t upload_cnt = 0;
	
	upload_cnt++;
	
	frame->count = upload_cnt;
	
	crc_buf[0] = frame->ID;
	crc_buf[1] = (frame->ID >> 8) & 0x00FF;
	
	for(uint8_t i=2; i<(frame->length); i++)
	{
		crc_buf[i] = *(databuf_p++);
	}
	
	crc_value = GetCRC((uint8_t*)(crc_buf), frame->length);
	
	frame->CRC_H = ((crc_value >> 8) & 0x00FF);
	frame->CRC_L = (crc_value & 0x00FF);
	
	#if 1
	ringBufWrite(bufhdl, (char*)frame, 6);
	ringBufWrite(bufhdl, (char*)crc_buf, frame->length);
    ringBufWrite(bufhdl, (char*)(&frame->CRC_L), 1);
	ringBufWrite(bufhdl, (char*)(&frame->CRC_H), 1);
	#endif
	
}





/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_data_monitor(STR_RINGBUF* send_bufHdl)
{	
	
	// if hmi data monitor cmd is timeout, stop datalist transmit.
	hmi_handle.monitor_cnt++;

	if(hmi_handle.monitor_cnt > TIMEOUT_DATA_MONITOR)
	{
		hmi_handle.monitor_en = 0;
		hmi_handle.monitor_cnt = TIMEOUT_DATA_MONITOR;
	}
	
	hmi_handle.monitor_interval++;
	
	// datalist update and transmit.
	if((hmi_handle.monitor_en == 1) && (hmi_handle.monitor_interval > HMI_MINITOR_INTERVAL))
	{
		static uint16_t index_cnt = 0;
		static uint16_t data_addr = 0;

		hmi_handle.monitor_interval = 0;
				
		hmi_data_transmit.databuf = &datalist.data[0];
		
		// ---------------------minitor data upload--------------------
		if(index_cnt < HMI_MINITOR_DATA_GROUP)
		{			
			if(index_cnt == 0)
			{
				hmi_handle.monitor_heartbeat++;
				hmi_handle.monitor_heartbeat %= 256;
			}
			
			datalist.Data1 = *(hmi_handle.monitor_data + (data_addr++));
			datalist.Data2 = *(hmi_handle.monitor_data + (data_addr++));
			datalist.Data3 = *(hmi_handle.monitor_data + (data_addr++));
			
			datalist.Index = index_cnt;
			
			data_addr %= HMI_MINITOR_DATA_MAX;
		}
		
		else if(index_cnt == HMI_MINITOR_DATA_GROUP)
		{
			index_cnt = HMI_MINITOR_FAULT_INDEX - 1;
			
			datalist.Data1 = 0;
			datalist.Data2 = 0;
			datalist.Data3 = 0;
			datalist.Index = index_cnt;
		}
		
		// ---------------- now fault data upload -----------------------
		else if(index_cnt == HMI_MINITOR_FAULT_INDEX)
		{
			
			datalist.Data1 = (hmi_handle.monitor_fault_now & 0x0000FFFF);
			datalist.Data2 = ((hmi_handle.monitor_fault_now >> 16) & 0x0000FFFF);
			datalist.Data3 = 0;
			
			datalist.Index = index_cnt;
		}
		
		// ------------- history fault data upload ---------------------
		else if(index_cnt == HMI_MINITOR_HISTORY_INDEX)
		{
			datalist.Data1 = (hmi_handle.monitor_fault_his & 0x0000FFFF);
			datalist.Data2 = ((hmi_handle.monitor_fault_his >> 16) & 0x0000FFFF);
			datalist.Data3 = 0;
			
			datalist.Index = index_cnt;
		}
		
		index_cnt++;
		index_cnt %= HMI_MINITOR_INDEX_MAX;
		
		datalist.Index += HMI_MINITOR_INDEX_OFFSET;
		
		send_buf_packing(send_bufHdl, &hmi_data_transmit);
	}
}



/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/
void hmi_param_upload(STR_RINGBUF* send_bufHdl)
{
	static uint16_t param_index = 0;
	static uint16_t param_cnt = 0;
	static uint16_t info_cnt  = 0;	
	
	if(hmi_handle.readAll_en == 1)
	{
		hmi_data_transmit.databuf = &paramlist.data[0];
		
		if(param_index < HMI_PARAM_DATA_GROUP)
		{
			paramlist.Data1 = 0x8000 + hmi_handle.monitor_param[param_cnt++];
			paramlist.Data2 = 0x8000 + hmi_handle.monitor_param[param_cnt++];
			paramlist.Data3 = 0x8000 + hmi_handle.monitor_param[param_cnt++];
			paramlist.Index = param_index;
			
			param_index++;
			
			if(!(param_index < HMI_PARAM_DATA_GROUP))
			{
				param_index = HMI_PRODUCT_INFO_INDEX;
			}
		}
		else if(param_index <= HMI_PRODUCT_INFO_INDEX_MAX)
		{
			paramlist.Data1 = 0 + hmi_handle.product_info[info_cnt++];
			paramlist.Data2 = 0 + hmi_handle.product_info[info_cnt++];
			paramlist.Data3 = 0 + hmi_handle.product_info[info_cnt++];
			paramlist.Index = param_index;			
			
			param_index++;
		}
		else
		{
			param_index = 0;
			param_cnt = 0;
			info_cnt = 0;
			hmi_handle.readAll_en = 0;
			
			memset((void *)&paramlist, 0, sizeof(paramlist));
			
			return;
		}
		
		paramlist.Index += HMI_PARAM_INDEX_OFFSET;
		send_buf_packing(send_bufHdl, &hmi_data_transmit);
	}
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_keyctrl_analysis(uint8_t *datatemp)
{
	hmi_handle.keyctrl_en = 1;
	hmi_handle.keyctrl_cnt = 0;
	
	switch(datatemp[1])
	{
		case HMI_KEY_FUN:
			byte_data_copy(&keycmd.data[0], datatemp, 8);
			break;
		
		case HMI_KEY_VALUE:
			byte_data_copy(&keyValue.data[0], datatemp, 8);
			break;
		
		case HMI_KEY_REF1:
			byte_data_copy(&keyRefX1.data[0], datatemp, 8);
			break;
		
		case HMI_KEY_REF2:
			byte_data_copy(&keyRefX2.data[0], datatemp, 8);
			break;
	}	
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none

*/
void get_hmi_keystatus(uint8_t *datatemp, ENUM_HMI_KEY_TYPE key_type)
{
	switch(key_type)
	{
		case HMI_KEY_FUN:
			byte_data_copy(datatemp, &keycmd.data[0], 8);
			break;
		
		case HMI_KEY_VALUE:
			byte_data_copy(datatemp, &keyValue.data[0], 8);
			break;
		
		case HMI_KEY_REF1:
			byte_data_copy(datatemp, &keyRefX1.data[0], 8);
			break;
		
		case HMI_KEY_REF2:
			byte_data_copy(datatemp, &keyRefX2.data[0], 8);
			break;
	}
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

uint8_t get_hmi_keyenable(void)
{
	return hmi_handle.keyctrl_en;
}



/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_keyctrl_timeout_check(void)
{
	hmi_handle.keyctrl_cnt++;
	
	if(hmi_handle.keyctrl_cnt > TIMEOUT_KEY_CTRL)
	{
		hmi_handle.keyctrl_en = 0;
		hmi_handle.keyctrl_cnt = TIMEOUT_KEY_CTRL;
		
		memset((void *)&keycmd,   0, sizeof(keycmd));
		memset((void *)&keyValue, 0, sizeof(keyValue));
		memset((void *)&keyRefX1, 0, sizeof(keyRefX1));
		memset((void *)&keyRefX2, 0, sizeof(keyRefX2));
	}
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

static uint16_t index_reCalculate(uint16_t index)
{
	uint16_t data_num = 0;
	uint16_t index_A = 0;
	uint16_t index_B = 0;
	
	index_A = index / (8 * 6);
	index_B = (index % (8 * 6)) / 16;
	
	data_num = (index_A  - HMI_MINITOR_INDEX_OFFSET) * 3 + index_B;
	
	if(data_num >= HMI_MINITOR_DATA_MAX)
	{
		data_num = HMI_MINITOR_DATA_MAX - 1;
	}
	
	return data_num;
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

static void plot_status_update(STR_HMI_HANDLE* hmiHdl, uint16_t plot_num, uint16_t index)
{
	hmiHdl->plot_flg[plot_num] = 1;
	hmiHdl->plot_timecnt[plot_num] = 0;
	hmiHdl->plot_index[plot_num] = index;
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_plot_analysis(uint8_t* datatemp)
{	
	uint16_t plot_num;
	
	byte_data_copy(plotcmd.data, datatemp, 8);
	
	if(plotcmd.Index1 != 0)
	{
		plot_num = index_reCalculate(plotcmd.Index1);
		plot_status_update(&hmi_handle, plot_num, plotcmd.Index1);
	}
	
	if(plotcmd.Index2 != 0)
	{
		plot_num = index_reCalculate(plotcmd.Index2);
		plot_status_update(&hmi_handle, plot_num, plotcmd.Index2);
	}
	
	if(plotcmd.Index3 != 0)
	{
		plot_num = index_reCalculate(plotcmd.Index3);
		plot_status_update(&hmi_handle, plot_num, plotcmd.Index3);		
	}
}



/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_plot_data_upload(STR_RINGBUF* send_bufHdl)
{
	// check timeout and update plot data send status -------------------------
	uint16_t data_plot_cnt = 0;
	uint16_t data_plot_temp[HMI_MINITOR_DATA_MAX];
	
	for(uint8_t i=0; i<HMI_MINITOR_DATA_MAX; i++)
	{
		hmi_handle.plot_timecnt[i]++;

		if(hmi_handle.plot_flg[i] == 1)
		{			
			if(hmi_handle.plot_timecnt[i] > TIMEOUT_PLOT)
			{
				hmi_handle.plot_flg[i] = 0;
			}
			else
			{
				data_plot_temp[data_plot_cnt] = i;
				data_plot_cnt++;
			}
		}		
	}

	// plot data frame packing ---------------------------------	
	for(uint8_t i=0; i<data_plot_cnt; i=i+2)
	{
		plotdata.Data1 = hmi_handle.monitor_data[data_plot_temp[i]];
		plotdata.Index1 = hmi_handle.plot_index[data_plot_temp[i]];
		
		if((i + 1) < data_plot_cnt)
		{
			plotdata.Data2 = hmi_handle.monitor_data[data_plot_temp[i+1]];
			plotdata.Index2 = hmi_handle.plot_index[data_plot_temp[i+1]];
		}
		
		hmi_plot_transmit.databuf = &plotdata.data[0];
		send_buf_packing(send_bufHdl, &hmi_plot_transmit);
		
		memset((void *)&plotdata, 0, sizeof(plotdata));
	}
}



/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_ota_cmd_analysis(uint8_t *datatemp, STR_RINGBUF* send_bufHdl)
{
	STR_HMI_FUNNUM  ota_cmd;
	STR_HMI_CMDACK  ota_ack;
	
	byte_data_copy(ota_cmd.data, datatemp, 8);	
	hmi_ack_transmit.databuf = &ota_ack.data[0];
	
	// OTA reset program
	if(hmi_ota_reset_handle())
	{
		ota_ack.ctrlRes = 5;
	}
	else
	{
		ota_ack.ctrlRes = 10;
		
		ota_ack.InsNum = HMI_OTA_CMD;
		ota_ack.xx = HMI_OTA_SHAKE;
		send_buf_packing(send_bufHdl, &hmi_ack_transmit);
	}
}




/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_param_write(uint8_t *datatemp, STR_RINGBUF* send_bufHdl)
{
	uint16_t write_addr = 0;
	uint16_t write_data = 0;
	uint8_t  write_res  = 0;
	
	STR_HMI_WRITEONE  write_one;
	STR_HMI_CMDACK    write_param_ack;
	
	byte_data_copy(write_one.data, datatemp, 8);	
	hmi_ack_transmit.databuf = &write_param_ack.data[0];
	
	// parameter write program
	// ...
	
	write_addr = write_one.addr + write_one.Index * 3 + HMI_PARAM_ADDR_OFFSET;
	write_data = write_one.value - 0x8000;
	
	write_res = hmi_param_write_handle(write_addr, write_data);

	write_param_ack.InsNum = HMI_WRITE_ONE;
	write_param_ack.xx = 0;
	write_param_ack.yy = 0;
	write_param_ack.writeRes = write_res;
	write_param_ack.paramAddr = write_one.addr;
	write_param_ack.paramIndex = write_one.Index;	
	
	send_buf_packing(send_bufHdl, &hmi_ack_transmit);
	
	// parameter write status
	param_write_flag = write_res;
}



/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_param_saveALL(STR_RINGBUF* send_bufHdl)
{
	if(hmi_param_save_handle() && param_write_flag)
	{
		STR_HMI_CMDACK    save_param_ack;

		hmi_ack_transmit.databuf = &save_param_ack.data[0];
		
		save_param_ack.InsNum = HMI_PARAM_SAVE;
		
		send_buf_packing(send_bufHdl, &hmi_ack_transmit);
		
		param_write_flag = 0;
	}
}









/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void hmi_comm_handle(STR_RINGBUF* rece_bufhdl, STR_RINGBUF* send_bufHdl)
{
	uint8_t rece_num = 0;
	
	hmi_datalist_update(&hmi_handle, HMI_MINITOR_DATA_NUM);

	// read data from rece_bufhdl, save as hmi data framework
	rece_num = rece_buf_analysis(rece_bufhdl, &hmi_frame_buffer[0]);
	
	for(uint8_t i=0; i<rece_num; i++)
	{
		switch(frame_buffer_payload[i][0])
		{
			case HMI_DATA_LIST:
				hmi_handle.monitor_en  = 1;
				hmi_handle.monitor_cnt = 0;
				break;
			
			case HMI_CTRL_CMD:	
				hmi_handle.keyctrl_en  = 1;
				hmi_handle.keyctrl_cnt = 0;
				hmi_keyctrl_analysis(&frame_buffer_payload[i][0]);
				break;
			
			case HMI_FLT_CLEAR:
				hmi_handle.faultclear = 1;
				break;
			
			case HMI_DATA_PLOT:	
				hmi_plot_analysis(&frame_buffer_payload[i][0]);
				break;
			
			case HMI_READ_ALL:					
				hmi_handle.readAll_en = 1;
				hmi_paramlist_update(&hmi_handle.monitor_param[0], HMI_PARAM_DATA_NUM);
				hmi_product_info_update(&hmi_handle.product_info[0], HMI_PRODUCT_INFO_NUM);
			
				break;
			
			case HMI_READ_ONE:			
				break;
			
			case HMI_WRITE_ONE:
				hmi_param_write(&frame_buffer_payload[i][0], send_bufHdl);
				break;
			
			case HMI_PARAM_SAVE:
				hmi_param_saveALL(send_bufHdl);
				break;
				
			case HMI_OTA_CMD:
				hmi_ota_cmd_analysis(&frame_buffer_payload[i][0], send_bufHdl);
				break;
			
			case HMI_USER_ACK:
				break;
			
			case HMI_USER_CMD:
				robot_comm_data_handle(&frame_buffer_payload[i][0], send_bufHdl);
				break;
			
			
			
			
		}
	}
	
	// hmi cycles check task
	
	if(hmi_handle.readAll_en == 1)	
	{
		hmi_param_upload(send_bufHdl);
	}
	else	
	{		
		hmi_data_monitor(send_bufHdl);
		hmi_plot_data_upload(send_bufHdl);
	}
	
	hmi_keyctrl_timeout_check();

}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

uint8_t get_hmi_faultclear(void)
{
	return hmi_handle.faultclear;
}


/*!
    \brief      
    \param[in]  none
    \param[out] none
    \retval     none
*/

void set_hmi_faultclear(uint8_t status)
{
	hmi_handle.faultclear = status;
}




















